package com.sec.etech.common.fanutil;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sec.etech.bpm.cust.mapper.EtechTaskOpinionExtMapper;
import com.sec.etech.bpm.cust.model.EtechTaskOpinionExt;
import com.sec.etech.common.service.Mail;
import com.sec.etech.org.service.EtechUserUtil;
import com.sec.etech.sys.util.ContextUtil;
import org.openbpm.base.core.util.AppUtil;
import org.openbpm.form.util.JdbcTemplateUtil;
import org.springframework.jdbc.core.JdbcTemplate;

import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class FanUtil {

    // 集合

    /**
     * @param mapList         传入的 mapList
     * @param keyName         从 mapList 中取值的键名，提取后值作为 HashMap 的键
     * @param valueName       从 mapList 中取值的键名，提取后值作为 HashMap 的值
     * @param isDelEmptyValue 提取值为空时（ NULL、空字符串、空白字符串），是否将其删除
     * @return
     */
    public static ConcurrentHashMap<String, String> mapListToHashMap(List<Map<String, Object>> mapList, String keyName, String valueName, Boolean isDelEmptyValue) {
        ConcurrentHashMap<String, String> hashMap = new ConcurrentHashMap<>();
        for (int i = 0; i < mapList.size(); i++) {
            String key = toStringIfNullToEmpty(mapList.get(i).get(keyName), true);
            String value = toStringIfNullToEmpty(mapList.get(i).get(valueName), true);

            if (isDelEmptyValue && StrUtil.isBlankOrUndefined(value)) {
                continue;
            }

            hashMap.put(key, value);
        }
        return hashMap;
    }


    /**
     * 重载方法， isDelEmptyValue 默认为 true。
     *
     * @return
     */
    public static ConcurrentHashMap<String, String> mapListToHashMap(List<Map<String, Object>> mapList, String keyName, String valueName) {
        return FanUtil.mapListToHashMap(mapList, keyName, valueName, true);
    }


    /**
     * @param mapList         传入的 mapList
     * @param entry           从 mapList 中取值的键名，提取后值作为 List 的值
     * @param isDelEmptyValue 提取值为空时（ NULL、空字符串、空白字符串），是否将其删除
     * @return
     */
    public static List<String> mapListToList(List<Map<String, Object>> mapList, String entry, Boolean isDelEmptyValue) {
        List<String> list = new ArrayList<>();
        for (Map<String, Object> item : mapList) {
            String value = toStringIfNullToEmpty(item.get(entry), true);
            if (isDelEmptyValue && StrUtil.isBlankOrUndefined(value)) {
                continue;
            }

            list.add(value);
        }
        return list;
    }

    /**
     * 重载方法， isDelEmptyValue 默认为 true。
     *
     * @return
     */
    public static List<String> mapListToList(List<Map<String, Object>> mapList, String entry) {
        return FanUtil.mapListToList(mapList, entry, true);
    }


    /**
     * 判断两个 List 的内容是否完全相等
     *
     * @param list1
     * @param list2
     * @return
     */
    public static Boolean isListEqual(List list1, List list2) {
        ArrayList delList = new ArrayList();
        delList.addAll(list1);
        delList.removeAll(list2);

        ArrayList addList = new ArrayList();
        addList.addAll(list2);
        addList.removeAll(list1);
        if (delList.size() == 0 && addList.size() == 0) {
            return true;
        }

        return false;
    }


    /**
     * 判断值是否在 list 中
     *
     * @param list
     * @param val
     * @return
     */
    public static Boolean isInList(List<String> list, String val) {
        for (String item : list) {
            if (item.equals(val)) {
                return true;
            }
        }

        return false;
    }


    public static HashSet<String> getAddSet(Set<String> newSet, Set<String> oldSet) {
        HashSet<String> addSet = new HashSet<>();
        addSet.addAll(newSet);
        addSet.removeAll(oldSet);

        return addSet;
    }


    public static HashSet<String> getDeleteSet(Set<String> newSet, Set<String> oldSet) {
        HashSet<String> deleteSet = new HashSet<>();
        deleteSet.addAll(oldSet);
        deleteSet.removeAll(newSet);

        return deleteSet;
    }

    public static HashSet<String> getInterSet(Set<String> newSet, Set<String> oldSet) {
        HashSet<String> deleteSet = new HashSet<>();
        deleteSet.addAll(oldSet);
        deleteSet.removeAll(newSet);


        HashSet<String> interSet = new HashSet<>();
        interSet.addAll(oldSet);
        interSet.removeAll(deleteSet);

        return interSet;
    }


    // 字符串

    /**
     * 重载方法，isTrim 默认为 true。
     *
     * @param object
     * @return
     */
    public static String toStringIfNullToEmpty(Object object) {
        return FanUtil.toStringIfNullToEmpty(object, true);
    }

    /**
     * @param object 任意对象，包括 null
     * @param isTrim 是否去除前后空格
     * @return
     */
    public static String toStringIfNullToEmpty(Object object, Boolean isTrim) {
        if (object == null) {
            return "";
        }

        if (isTrim) {
            return object.toString().trim();
        }

        return object.toString();
    }


    // Entity

    /**
     * 补全基础数据
     *
     * @param baseEntity
     */
    public static void setBaseData(BaseEntity baseEntity) {
        Date date = new Date();
        String currentUserId = ContextUtil.getCurrentUserId();
        baseEntity.setActive(true);
        baseEntity.setPostuid(currentUserId);
        baseEntity.setPostdate(date);
        baseEntity.setLastuid(currentUserId);
        baseEntity.setLastdate(date);
    }

    /**
     * 补全基础数据 JSONObject 重载
     *
     * @param jsonObject
     */
    public static void setBaseData(JSONObject jsonObject) {
        Date date = new Date();
        String currentUserId = ContextUtil.getCurrentUserId();
        jsonObject.put("active", "1");
        jsonObject.put("postuid", currentUserId);
        jsonObject.put("postdate", date);
        jsonObject.put("lastuid", currentUserId);
        jsonObject.put("lastdate", date);
    }


    // 异常

    /**
     * 异常调用栈转文本输出
     *
     * @param throwable 任意异常
     * @return
     */
    public static String getErrorInfoFromException(Throwable throwable) {
        try {
            StringWriter stringWriter = new StringWriter();
            PrintWriter printWriter = new PrintWriter(stringWriter);
            throwable.printStackTrace(printWriter);
            return "\r\n" + stringWriter.toString() + "\r\n";
        } catch (Exception e) {
            return "error in: [com.sec.etech.common.fanutil.FanUtil.getErrorInfoFromException], error message: [" + e.getMessage() + "]";
        }
    }

    /**
     * 捕获异常并发送邮件提醒。
     *
     * @param uid       收件人 id
     * @param subject   邮件标题
     * @param throwable 任意异常
     */
    public static void catchAndMail(String uid, String subject, Throwable throwable) {
        throwable.printStackTrace();
        new Mail(uid, "catchAndMail-" + subject, getErrorInfoFromException(throwable)).SendEmail();
    }

    public static void errorAndMail(String uid, String subject, String context) {
        new Mail(uid, "errorAndMail-" + subject, context).SendEmail();
    }

    // 用户
    public static List<String> getUidByRoleKey(String roleKey) {
        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");
        String sql = "SELECT a.user_id_ FROM `org_relation` AS a\n" +
                "LEFT JOIN org_role AS b ON a.role_id_ = b.id_\n" +
                "WHERE \n" +
                "a.status_ = 1 \n" +
                "AND b.enabled_ = 1 \n" +
                "AND b.alias_ ='" + roleKey + "'";
        List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);
        return mapListToList(mapList, "user_id_", true);
    }

    public static List<String> getDesignDprtPlannerId(String dprtId) {
        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");
        String sql = "SELECT b.uid FROM `proj_plantask_z_designdprt` AS a \n" +
                "LEFT JOIN proj_plantask_z_designdprt_planners AS b ON a.designdprtid = b.designdprtid\n" +
                "WHERE a.dprtid = " + dprtId;
        List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);
        return mapListToList(mapList, "uid", true);
    }


    // 组织
    public static String getGroupId(String uid) {
        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");

        String sql = StrUtil.format("SELECT group_id_ FROM `org_relation` WHERE type_ = 'groupUser' AND is_master_ = 1 AND user_id_ = '{}' ", uid);
        List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);
        if (mapList.size() != 1) {
            throw new RuntimeException(StrUtil.format("@getGroupId 用户所属部门为空或有多个！ sql=[ {} ]", sql));
        }

        return mapList.get(0).get("group_id_").toString();

    }

    public static String getParentGroupIdByGroupId(String groupId) {
        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");

        String sql = StrUtil.format("select parent_id_ from org_group where id_ = '{}'", groupId);
        List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);
        if (mapList.size() != 1) {
            throw new RuntimeException(StrUtil.format("@getParentGroupIdByGroupId 上级部门为空或有多个！ sql=[ {} ]", sql));
        }

        return mapList.get(0).get("parent_id_").toString();
    }

    public static String getParentGroupId(String uid) {
        return FanUtil.getParentGroupIdByGroupId(FanUtil.getGroupId(uid));
    }

    public static String getParentGroupName(String uid) {
        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");
        String sql = "SELECT TRIM(name_) FROM `org_group` WHERE id_ = '" + getParentGroupId(uid) + "'";
        return jdbcTemplate.queryForObject(sql, String.class);
    }

    public static String getRoleCodeById(String roleId) {
        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");
        String sql = "SELECT alias_ FROM `org_role` WHERE id_ = '" + roleId + "'";
        return jdbcTemplate.queryForObject(sql, String.class);
    }

    // 流程
    public static String getInstanceIdByTaskId(String taskId) {
        if (StrUtil.isBlankOrUndefined(taskId)) {
            throw new RuntimeException("getInstanceIdByTaskId() : taskId 为空！");
        }

        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");
        String sql = "SELECT inst_id_ AS bpmInstanceId FROM `bpm_task_opinion` WHERE task_id_ = '" + taskId + "'";
        List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);

        if (mapList.size() != 1) {
            throw new RuntimeException("getInstanceIdByTaskId() : taskId 查询的 BpmInstanceId 不唯一！");
        }

        return mapList.get(0).get("bpmInstanceId").toString();
    }

    public static String getSubjectByInstanceId(String instanceId) {
        if (StrUtil.isBlankOrUndefined(instanceId)) {
            throw new RuntimeException("getSubjectByInstanceId() : instanceId 为空！");
        }

        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");
        String sql = "SELECT IFNULL(subject_,'') AS `subject` FROM `bpm_instance` WHERE id_ = '" + instanceId + "'";
        List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);

        if (mapList.size() != 1) {
            throw new RuntimeException("getSubjectByInstanceId() : instanceId 查询的 subject 不唯一！");
        }

        return mapList.get(0).get("subject").toString();
    }


    public static String getTaskKeyByTaskId(String taskId) {
        if (StrUtil.isBlankOrUndefined(taskId)) {
            throw new RuntimeException("getTaskKeyByTaskId() : taskId 为空！");
        }

        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");
        String sql = "SELECT task_key_ FROM `bpm_task_opinion` WHERE task_id_ = '" + taskId + "'";
        List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);

        if (mapList.size() != 1) {
            throw new RuntimeException("getTaskKeyByTaskId() : 获取 task_key 不唯一！");
        }

        return mapList.get(0).get("task_key_").toString();

    }


    public static List<String> getRunningTaskId(String bpmInstanceId) {
        if (StrUtil.isBlankOrUndefined(bpmInstanceId)) {
            throw new RuntimeException("getRuningTaskId() : bpmInstanceId 为空！");
        }

        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");
        String sql = "SELECT task_id_ FROM `bpm_task` WHERE inst_id_ = '" + bpmInstanceId + "' ORDER BY id_ DESC;";
        List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);

        List<String> bpmInstanceIdList = FanUtil.mapListToList(mapList, "task_id_");
        return bpmInstanceIdList;

    }

    // 获取指定节点候选人
    // 节点多次激活时以最后一次为准
    public static List<String> getNodeAssignUidList(String bpmInstanceId, String nodeKey, String defaultUid) {
        EtechTaskOpinionExtMapper taskOpinionExtMapper = AppUtil.getBean(EtechTaskOpinionExtMapper.class);


        ArrayList<String> nodeUserIdList = new ArrayList<>();

        // SELECT assign_info_ FROM `bpm_task_opinion` WHERE inst_id_ = 'xxx' AND task_key_ = 'K2.2' ORDER BY id_ DESC LIMIT 1
        EtechTaskOpinionExt taskOpinion = taskOpinionExtMapper.selectOne(new LambdaQueryWrapper<EtechTaskOpinionExt>()
                .select(EtechTaskOpinionExt::getAssignInfo)
                .eq(EtechTaskOpinionExt::getInstId, bpmInstanceId)
                .eq(EtechTaskOpinionExt::getTaskKey, nodeKey)
                .orderByDesc(EtechTaskOpinionExt::getId)
                .last(" LIMIT 1")
        );

        if (taskOpinion != null && !StrUtil.isBlankOrUndefined(taskOpinion.getAssignInfo())) {
            String assignInfo = taskOpinion.getAssignInfo();

            String[] nodeAuthorArr = assignInfo.split(",");
            for (int i = 0; i < nodeAuthorArr.length; i++) {
                String item = nodeAuthorArr[i];
                String[] eachNodeAuthorArr = item.split("-");
                String type = eachNodeAuthorArr[0];
                String name = eachNodeAuthorArr[1];
                String id = eachNodeAuthorArr[2];

                if ("user".equalsIgnoreCase(type)) {
                    nodeUserIdList.add(id);

                } else if ("role".equalsIgnoreCase(type)) {
                    String roleCode = FanUtil.getRoleCodeById(id);
                    List<String> roleUserIdList = EtechUserUtil.getUserIdsByRoleCode(roleCode);
                    nodeUserIdList.addAll(roleUserIdList);
                }
            }

        } else {
            nodeUserIdList.add(defaultUid);

        }


        return nodeUserIdList;
    }

    // 获取指定节点处理人
    // 节点多次激活时以最后一次为准
    public static String getNodeApproveUid(String bpmInstanceId, String nodeKey, String defaultUid) {
        EtechTaskOpinionExtMapper taskOpinionExtMapper = AppUtil.getBean(EtechTaskOpinionExtMapper.class);

        // SELECT approver_ FROM `bpm_task_opinion` WHERE inst_id_ = 'xxx' AND task_key_ = 'K2.2' ORDER BY id_ DESC LIMIT 1
        EtechTaskOpinionExt taskOpinion = taskOpinionExtMapper.selectOne(new LambdaQueryWrapper<EtechTaskOpinionExt>()
                .select(EtechTaskOpinionExt::getApprover)
                .eq(EtechTaskOpinionExt::getInstId, bpmInstanceId)
                .eq(EtechTaskOpinionExt::getTaskKey, nodeKey)
                .orderByDesc(EtechTaskOpinionExt::getId)
                .last(" LIMIT 1")
        );

        if (taskOpinion != null && !StrUtil.isBlankOrUndefined(taskOpinion.getApprover())) {
            return taskOpinion.getApprover();

        } else {
            return defaultUid;

        }

    }


    // 文件
    public static void renameFile(String fileId, String newName) {
        if (StrUtil.isBlankOrUndefined(fileId)) {
            throw new RuntimeException(StrUtil.format("@renameFile  fileId 为空！"));
        }

        JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");
        String sql = "UPDATE `sys_file` SET name_ ='{}' WHERE id_='{}';";
        jdbcTemplate.execute(StrUtil.format(sql, newName, fileId));

    }


    /**
     * 深拷贝，即将克隆全新的list，原来的地址不一样
     *
     * @param src
     * @return List<T>
     * @author PengMaochang
     * @date 2021/9/30 10:20
     */
    public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(src);

        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in = new ObjectInputStream(byteIn);
        @SuppressWarnings("unchecked")
        List<T> dest = (List<T>) in.readObject();
        return dest;
    }


}
